from decimal import Decimal

from administrators.models import Userinfo
from utils.tools import ParamCheck
from django.db import transaction
from django.db.models import CharField, F, Sum
from django.db.models.functions import Cast
import json
from administrators.views.token_check import verify_token  # 注意，这个是从管理应用引入的
from django.views.decorators.http import require_http_methods
from utils.enums import SCE
from utils.result import R
from datetime import date
import logging
# ---------------------------------------------------------------------
from inventory.models import MaterialGroup, Material, Record, Handle, Summary

logger = logging.getLogger('inventory')


# 查询某物料分组当天的总计进或出
@verify_token()
@require_http_methods(['POST'])
def summary_material_group_inout(request, user_id: int):
    data = json.loads(request.body)
    material_group_id = ParamCheck.int(data.get('material_group_id'))
    actual_date = ParamCheck.date(data.get('actual_date'))
    # 类型 [{'trend': False, 'a1': Decimal('4.880')}, {'trend': True, 'a1': Decimal('1026.260')}]
    temp1 = list(Record.objects
                 .filter(actual_date=actual_date, material__group_id=material_group_id)
                 .values('trend')
                 .annotate(a1=Sum('weight', default=0)))
    result = {False: Decimal('0'), True: Decimal('0')}
    for item in temp1:
        result[item['trend']] = item['a1']
    in_num = result[False]
    out_num = result[True]
    return R.success('查询成功').data({'in': in_num, 'out': out_num})


# 总结表增删改查
@verify_token()
@require_http_methods(['POST'])
def summary_crud(request, user_id: int):
    data = json.loads(request.body)
    user_obj = Userinfo.objects.get(id=user_id)
    match data['mode']:
        case 'create':
            data = data.get('create')
            actual_date = ParamCheck.date(data.get('actual_date'))
            material_group_id = ParamCheck.int(data.get('material_group_id'))
            inbound = ParamCheck.decimal(data.get('inbound'))
            outbound = ParamCheck.decimal(data.get('outbound'))
            other_in = ParamCheck.decimal(data.get('other_in'))
            other_out = ParamCheck.decimal(data.get('other_out'))
            remark = ParamCheck.str(data.get('remark'), length=(0, 100))
            try:
                material_group_obj = MaterialGroup.objects.get(id=material_group_id)
                # 如果该物料在该日期已经存在记录，则不允许创建新纪录
                if Summary.objects.filter(material_group=material_group_obj, actual_date=actual_date).exists():
                    return R.error(SCE.no_enum, '当前物料已经存在相关记录，不可重复创建').data()
                Summary(
                    actual_date = actual_date,
                    material_group = material_group_obj,
                    inbound = inbound,
                    outbound = outbound,
                    other_in = other_in,
                    other_out = other_out,
                    total_out = outbound - other_in + other_out,
                    remark = remark,
                    operate_date = date.today(),
                    operator = user_obj,
                ).save()
                return R.success('记录创建成功').data()
            except MaterialGroup.DoesNotExist:
                return R.error(SCE.no_enum, '物料分组不存在').data()
            except Exception:
                return R.error(SCE.no_enum, '异常故障，请联系管理员').data()

        case 'delete':
            data = data.get('delete')
            summary_id = ParamCheck.int(data.get('summary_id'))
            try:
                with transaction.atomic():
                    record_obj = Summary.objects.get(id=summary_id)
                    record_obj.delete()
                    return R.success('记录删除成功').data()
            except Record.DoesNotExist:
                return R.error(SCE.no_enum, '记录不存在，请刷新后重新选择').data()
            except Exception as e:
                return R.error(SCE.no_enum, '异常故障，请联系管理员').data()

        case 'update':
            data = data.get('update')
            # 允许更改任何项目
            summary_id = ParamCheck.int(data.get('summary_id'))
            actual_date = ParamCheck.date(data.get('actual_date'))
            material_group_id = ParamCheck.int(data.get('material_group_id'))
            inbound = ParamCheck.decimal(data.get('inbound'))
            outbound = ParamCheck.decimal(data.get('outbound'))
            other_in = ParamCheck.decimal(data.get('other_in'))
            other_out = ParamCheck.decimal(data.get('other_out'))
            remark = ParamCheck.str(data.get('remark'), length=(0, 100))
            try:
                with transaction.atomic():
                    # 如果该物料在该日期没有记录，则无法进行修改
                    material_group_obj = MaterialGroup.objects.get(id=material_group_id)
                    Summary_obj = Summary.objects.get(id=summary_id)
                    if Summary_obj.actual_date != actual_date:
                        if Summary.objects.filter(material_group=material_group_obj, actual_date=actual_date).exists():
                            return R.error(SCE.no_enum, '修改完成的日期已经存在记录，不可修改').data()
                    # 开始修改
                    summary_obj = Summary.objects.get(id=summary_id)
                    summary_obj.actual_date = actual_date
                    summary_obj.material_group = material_group_obj
                    summary_obj.inbound = inbound
                    summary_obj.outbound = outbound
                    summary_obj.other_in = other_in
                    summary_obj.other_out = other_out
                    summary_obj.total_out = outbound - other_in + other_out
                    summary_obj.remark = remark
                    summary_obj.operate_date = date.today()
                    summary_obj.operator = user_obj
                    summary_obj.save()
                    return R.success('记录修改成功').data()
            except Summary.DoesNotExist:
                return R.error(SCE.no_enum, '要修改的记录不存在').data()
            except MaterialGroup.DoesNotExist:
                return R.error(SCE.no_enum, '所选择的物料不存在').data()
            except Exception as e:
                print(e)

        case 'read':
            return R.error(SCE.no_enum, '功能尚未开发').data()

        case _:
            return R.error(SCE.ParamError).data()


# 总结表模糊查询
@verify_token()
@require_http_methods(['POST'])
def summary_fuzzy_search(request, user_id: str):
    data = json.loads(request.body)
    material_group_id = ParamCheck.int(data.get('material_group_id'), force=False)  # 物料分组
    operate_date = ParamCheck.date_range(data.get('operate_date'), force=False)
    actual_date = ParamCheck.date_range(data.get('actual_date'), force=False)
    start = ParamCheck.int(data['start'])
    stop = ParamCheck.int(data['stop'])

    result = Summary.objects

    if material_group_id is not None:
        result = result.filter(group_id=material_group_id)
    if operate_date is not None:
        result = result.filter(operate_date__gte=operate_date[0], operate_date__lte=operate_date[1])
    if actual_date is not None:
        result = result.filter(actual_date__gte=actual_date[0], actual_date__lte=actual_date[1])

    result = result \
        .annotate(operator_name=F('operator__username'), material_group_name=F('material_group__name'),
                  ) \
        .values('id', 'operator_name', 'material_group_name', 'material_group_id', 'inbound', 'outbound', 'other_in',
                'other_out', 'total_out', 'remark', 'material_group_id',
                operate_date_=Cast('operate_date', CharField()),
                actual_date_=Cast('actual_date', CharField())).order_by('actual_date')

    total = result.count()
    result = result[start: stop]
    return R.success('总结表搜索成功').data({'result': list(result), 'total': total})
